package trystero.lib.component.parser;

import java.util.Vector;
import java.io.InputStream;
import java.io.InputStreamReader;

import org.json.JSONObject;
import org.json.JSONArray;
import org.json.JSONTokener;

import trystero.lib.component.ReaderItem;
import trystero.lib.component.ReaderComment;
import trystero.lib.component.StreamContents;
import trystero.lib.component.ReaderText;
import trystero.lib.component.ReaderLink;
import trystero.lib.component.ReaderUser;
import trystero.lib.component.ReaderStream;

public class StreamContentsParser
{
   InputStream stream;

   public StreamContentsParser(InputStream stream)
   {
      this.stream = stream;
   }

   public StreamContents parse() throws Exception
   {
      JSONTokener t = new JSONTokener(new InputStreamReader(this.stream));
      JSONObject o = new JSONObject(t);
      return this.parse(o);
   }

   public StreamContents parse(JSONObject o) throws Exception
   {
      StreamContents list = new StreamContents();

      list.direction((String)o.get("direction"));
      list.id((String)o.get("id"));
      list.title((String)o.get("title"));
      list.continuation((String)o.opt("continuation"));
      list.author((String)o.opt("author"));
      list.updated(((Integer)o.get("updated")).longValue());

      JSONArray items = (JSONArray)o.get("items");
      list.items(this.parseItemVector(items));

      return list;
   }

   public Vector parseItemVector(JSONArray a) throws Exception
   {
      Vector v = new Vector();

      for(int i = 0; i < a.length(); i++)
      {
	 ReaderItem item = this.parseItem((JSONObject)a.get(i)); 
	 v.add(item);
      }

      return v;
   }

   public ReaderItem parseItem(JSONObject o) throws Exception
   {
      ReaderItem item = new ReaderItem();
      item.crawled(Long.parseLong((String)o.get("crawlTimeMsec")));
      item.id((String)o.get("id"));

      // categories
      item.categories(new Vector());

      JSONArray categories = (JSONArray)o.get("categories");
      for(int i = 0; i < categories.length(); i++)
      {
	  item.categories().add((String)categories.get(i));
      }

      item.title((String)o.get("title"));
      item.published(((Integer)o.get("published")).longValue()); 
      item.updated(((Integer)o.get("updated")).longValue()); 

      JSONArray enclosure = (JSONArray)o.opt("enclosure");
      if(enclosure != null)
         item.enclosure(this.parseLinkVector(enclosure));

      JSONArray alternate = (JSONArray)o.get("alternate");
      item.alternate(parseLinkVector(alternate));

      JSONArray via = (JSONArray)o.opt("via");
      if(via != null)
         item.via(this.parseLinkVector(via));

      ReaderText summary = this.parseSummary((JSONObject)o.opt("content"), 
	 (JSONObject)o.opt("summary"));
      item.summary(summary);

      item.author((String)o.opt("author"));

      JSONArray liked = (JSONArray)o.get("likingUsers");
      item.liked(this.parseUserVector(liked));

      JSONArray comments = (JSONArray)o.get("comments");
      item.comments(this.parseCommentVector(comments));

      item.origin(this.parseStream((JSONObject)o.get("origin")));

      return item;
   }

   public ReaderText parseSummary(JSONObject content, JSONObject summary) 
      throws Exception
   {
      ReaderText text = new ReaderText();
      
      if(content == null && summary != null)
      {
         text.direction((String)summary.get("direction"));
         text.content((String)summary.get("content"));
      }
      else if(content != null)
      {
	 // When both content and summary are provided, 
	 // assume the "content" is more complete than the "summary".

         text.direction((String)content.get("direction"));
         text.content((String)content.get("content"));
      }
      else
      {
	 text = null;
      }

      return text;
   }

   public Vector parseLinkVector(JSONArray a) throws Exception
   {
      Vector v = new Vector();

      for(int i = 0; i < a.length(); i++)
      {
         ReaderLink link = this.parseLink((JSONObject)a.get(i));
   
         v.add(link);
      }

      return v;
   }

   public ReaderLink parseLink(JSONObject o) throws Exception
   {
      ReaderLink link = new ReaderLink();
      link.href((String)o.get("href"));
      link.type((String)o.opt("type"));
      link.title((String)o.opt("title"));
      
      String length = (String)o.opt("length");
      if(length != null)
         link.length(Long.parseLong(length));

      return link;
   }

   public Vector parseCommentVector(JSONArray a) throws Exception
   {
      Vector v = new Vector();

      for(int i = 0; i < a.length(); i++)
      {
         ReaderComment comment = this.parseComment((JSONObject)a.get(i));
   
         v.add(comment);
      }

      return v;
   }

   public ReaderComment parseComment(JSONObject o) throws Exception
   {
      ReaderComment comment = new ReaderComment();

      comment.id((String)o.get("id"));
      comment.content((String)o.get("plainContent"));
      comment.html((String)o.get("htmlContent"));
      comment.author((String)o.get("author"));
      comment.user((String)o.get("userId"));
      comment.profile((String)o.get("profileId"));
      comment.params((String)o.get("profileCardParams"));
      comment.venue((String)o.get("venueStreamId"));
      comment.created(((Integer)o.get("createdTime")).longValue());
      comment.modified(((Integer)o.get("modifiedTime")).longValue());

      return comment;
   }

   public Vector parseUserVector(JSONArray a) throws Exception
   {
      Vector v = new Vector();

      for(int i = 0; i < a.length(); i++)
      {
         ReaderUser user = this.parseUser((JSONObject)a.get(i));
   
         v.add(user);
      }

      return v;
   }

   public ReaderUser parseUser(JSONObject o) throws Exception
   {
      ReaderUser user = new ReaderUser();

      user.user((String)o.get("userId"));

      return user;
   }

   public ReaderStream parseStream(JSONObject o) throws Exception
   {
      ReaderStream stream = new ReaderStream();

      stream.stream((String)o.get("streamId"));
      stream.title((String)o.get("title"));
      stream.url((String)o.get("htmlUrl"));

      return stream;
   }
}
